/*
    日志器模块：
        
*/

#pragma once

#define _GUN_SOURCE

#include <thread>
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <memory>
#include <unordered_map>

#include "util.hpp"
#include "level.hpp"
#include "message.hpp"
#include "sink.hpp"
#include "format.hpp"
#include "looper.hpp"

namespace iceLogs
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, logLevel::value level, Formatter::ptr &formatter, std::vector<logSink::ptr> &sinks)
        :_logger_name(logger_name)
        ,_limit_level(level)
        ,_formatter(formatter)
        ,_sinks(sinks.begin(), sinks.end())
        {}
        const std::string& name()
        {
            return _logger_name;
        }
        //完成构造日志消息对象过程并进行格式化，得到格式化后的日志消息字符串--进行落地输出
        void Debug(const std::string &file, size_t line, const std::string& fmt, ...)
        {
            //通过传入参数构造出一个日志消息对象，进行日志格式化，最终落地
            //1.判断当前日志等级是否达到输出要求
            if(logLevel::value::DEBUG < _limit_level) {return ;}
            //2.对fmt格式化字符串和不定参进行字符串组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error!!!\n";
                return ;
            }
            va_end(ap);
            serialize(logLevel::value::DEBUG, file, line, res);
            free(res);
        }
        void Info(const std::string &file, size_t line, const std::string& fmt, ...)
        {
            //通过传入参数构造出一个日志消息对象，进行日志格式化，最终落地
            //1.判断当前日志等级是否达到输出要求
            if(logLevel::value::INFO < _limit_level) {return ;}
            //2.对fmt格式化字符串和不定参进行字符串组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error!!!\n";
                return ;
            }
            va_end(ap);
            serialize(logLevel::value::INFO, file, line, res);
            free(res);
        }
        void Warn(const std::string &file, size_t line, const std::string& fmt, ...)
        {
            //通过传入参数构造出一个日志消息对象，进行日志格式化，最终落地
            //1.判断当前日志等级是否达到输出要求
            if(logLevel::value::WARG < _limit_level) {return ;}
            //2.对fmt格式化字符串和不定参进行字符串组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error!!!\n";
                return ;
            }
            va_end(ap);
            serialize(logLevel::value::WARG, file, line, res);
            free(res);
        }
        void Error(const std::string &file, size_t line, const std::string& fmt, ...)
        {
            //通过传入参数构造出一个日志消息对象，进行日志格式化，最终落地
            //1.判断当前日志等级是否达到输出要求
            if(logLevel::value::ERROR < _limit_level) {return ;}
            //2.对fmt格式化字符串和不定参进行字符串组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error!!!\n";
                return ;
            }
            va_end(ap);
            serialize(logLevel::value::ERROR, file, line, res);
            free(res);
        }
        void Fatal(const std::string &file, size_t line, const std::string& fmt, ...)
        {
            //通过传入参数构造出一个日志消息对象，进行日志格式化，最终落地
            //1.判断当前日志等级是否达到输出要求
            if(logLevel::value::FATAL < _limit_level) {return ;}
            //2.对fmt格式化字符串和不定参进行字符串组织，得到日志消息字符串
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error!!!\n";
                return ;
            }
            va_end(ap);
            serialize(logLevel::value::FATAL, file, line, res);
            free(res);
        }

    protected:
        void serialize(logLevel::value level, const std::string& file, size_t line, char* str)
        {
            //3.构造LogMsg对象
            logMsg msg(level, file, line, _logger_name, str);
            //4.通过格式化工具对LogMsg对象进行格式化，得到格式化后的日志消息字符串
            std::stringstream ss;
            _formatter->format(ss, msg);
            //5.日志落地
            log(ss.str().c_str(), ss.str().size()); 
        }
        //抽象接口完成实际落地输出--不同的日志器会有不同的落地方式
        virtual void log(const char* data, size_t len) = 0;
    protected:
        std::mutex _mutex;
        std::string _logger_name;
        std::atomic<logLevel::value> _limit_level;
        Formatter::ptr _formatter;
        std::vector<logSink::ptr> _sinks;
    };

    class SyncLogger : public Logger
    {
        public:
            SyncLogger(const std::string& logger_name, logLevel::value level, Formatter::ptr &formatter, std::vector<logSink::ptr> &sinks)
            :Logger(logger_name, level, formatter, sinks){}
        protected:
            void log(const char* data, size_t len)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if(_sinks.empty()) return ;
                for(auto &sink : _sinks)
                {
                    sink->log(data, len);
                }
            }
    };

    class ASyncLogger : public Logger
    {
        public:
            ASyncLogger(const std::string& logger_name, logLevel::value level, Formatter::ptr &formatter, std::vector<logSink::ptr> &sinks, asyncType looper_type)
            :Logger(logger_name, level, formatter, sinks)
            , _looper(std::make_shared<AsyncLooper>(std::bind(&ASyncLogger::realLog, this, std::placeholders::_1), looper_type)){}

            void log(const char* data, size_t len)
            {
                _looper->push(data, len);
            }

            void realLog(Buffer &buffer)
            {
                if(_sinks.empty()) return ;
                for(auto& sink : _sinks)
                {
                    sink->log(buffer.begin(), buffer.readAbleSize());
                }
            }

        private:
            AsyncLooper::ptr _looper;
            
    };
    

    /*
        受用建造者模式，抽象出建造者类，不需要用户直接去构造日志器，简化使用复杂度
        1.抽象建造者类
            1.设置日志器等级
            2.将不同类型的日志器的创建放到同一个日志器建造者中完成
        2.派生出具体的建造者类，局部日志器建造者和全局日志器建造者（后面添加了全局单例管理器之后，将日志器添加全局管理）
    */

   enum loggerType
   {
        SYCN,
        ASYNC
   };
   class LoggerBuider
   {
    public:
        LoggerBuider()
        :_limit_level(logLevel::value::DEBUG)
        ,_logger_type(loggerType::SYCN)
        ,_looper_type(asyncType::ASYNC_SAFE)
        {}
        void BuildLoggerType(loggerType type) { _logger_type = type; }
        void BuildEnableUnSafeAsync(asyncType looperType) { _looper_type = asyncType::ASYNE_UNSAFE; }
        void BuildLoggerName(const std::string& loggerName)
        {
            _logger_name = loggerName;
        }
        void BuildLoggerLevel(logLevel::value level)
        {
            _limit_level = level;
        }
        void BuildFormatter(const std::string& pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }
        template <typename SinkType, typename ...Args>
        void BuildSink(Args &&...args)
        {
            logSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        virtual Logger::ptr Build() = 0;
    protected:
        asyncType _looper_type;
        loggerType _logger_type;
        std::string _logger_name;
        logLevel::value _limit_level;
        Formatter::ptr _formatter;
        std::vector<logSink::ptr> _sinks;
   };

   class LocalLoggerBuider : public LoggerBuider
   {
    public:
        Logger::ptr Build() override 
        {
            assert(!_logger_name.empty());
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                BuildSink<StdoutSink>();
            }
            if(_logger_type == loggerType::ASYNC)
            {
                return std::make_shared<ASyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
        }
   };


   class LoggerManager
   {
        public:
            static LoggerManager& getInstance()
            {
                static LoggerManager eton;
                return eton;
            }
            void addLogger(Logger::ptr &logger)
            {
                if(hasLogger(logger->name()) == true) return ;
                std::unique_lock<std::mutex> lock(_mutex);
                _loggers.insert(std::make_pair(logger->name(), logger));
            }
            bool hasLogger(const std::string &name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _loggers.find(name);
                if(it == _loggers.end())
                {
                    return false;
                }

                return true;
            }

            Logger::ptr getLogger(const std::string &name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _loggers.find(name);
                if(it == _loggers.end())
                {
                    return Logger::ptr();
                }

                return it->second;
            }

            Logger::ptr rootLogger()
            {
                return _root_logger;
            }
        private:
            LoggerManager()
            {
                std::unique_ptr<iceLogs::LoggerBuider> builder(new iceLogs::LocalLoggerBuider());
                builder->BuildLoggerName("root");
                _root_logger = builder->Build();
                _loggers.insert(std::make_pair("root", _root_logger));
            }
        private:
            std::mutex _mutex;
            Logger::ptr _root_logger;//默认日志器
            std::unordered_map<std::string, Logger::ptr> _loggers;
   };


   class GlobalLoggerBuider : public LoggerBuider
   {
    public:
        Logger::ptr Build() override 
        {
            assert(!_logger_name.empty());
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                BuildSink<StdoutSink>();
            }
            Logger::ptr logger;
            if(_logger_type == loggerType::ASYNC)
            {
                logger = std::make_shared<ASyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else 
            {
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
   };
}
